using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

namespace OpenWaves.Caching
{
    public class MultilevelCache<T> : ICache<T> where T : class
    {
        private readonly ICache<MultilevelCacheEntry<T>>[] caches;

        public MultilevelCache(IEnumerable<ICache<MultilevelCacheEntry<T>>> caches)
        {
            Contract.Requires<ArgumentNullException>(caches != null);
            this.caches = caches.ToArray();
        }

        public MultilevelCache(params ICache<MultilevelCacheEntry<T>>[] caches)
        {
            Contract.Requires<ArgumentNullException>(caches != null);
            this.caches = caches;
        }

        public void InsertValue(string key, T value, DateTime absoluteExpiration)
        {
            foreach (var cache in this.caches)
            {
                cache.InsertValue(key, new MultilevelCacheEntry<T>(value, absoluteExpiration), absoluteExpiration);
            }
        }

        public void EvictValue(string key)
        {
            foreach (var cache in this.caches)
            {
                cache.EvictValue(key);
            }
        }

        public T GetValue(string key)
        {
            for (var i = 0; i < caches.Length; i++ )
            {
                var cache = this.caches[i];
                
                var entry = cache.GetValue(key);
                if (entry != null)
                {
                    for (var j = 0; j < i; j++ )
                    {
                        this.caches[j].InsertValue(key, entry, entry.AbsoluteExpiration);    
                    }
                    
                    return entry.Value;                    
                }
            }

            return null;
        }
    }
}